package io.sundial.console;

import io.regent.commons.jwt.JWT;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 异常拦截器
 *
 * @author 杨昌沛 646742615@qq.com
 * @date 2018-07-04 13:40
 **/
@Aspect
@Component
public class VerificationInterceptor {

    @Pointcut("execution(public io.sundial.console.ApiResult+ io.sundial..*Controller.*(..)) && !execution(* io.sundial.console.authentication.AuthenticationController.*(..))")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) throw new IllegalStateException();
        HttpServletRequest request = attributes.getRequest();
        String accessToken = request.getHeader("Access-Token");
        if (accessToken == null) accessToken = request.getParameter("access_token");
        if (StringUtils.isEmpty(accessToken)) {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            ApiResult result = (ApiResult) method.getReturnType().newInstance();
            return result.error(403, "Invalid Access Token");
        }
        JWT jwt = JWT.decode(accessToken);
        Number issuedAt = jwt.getPayload(JWT.IAT);
        Number expiresIn = jwt.getPayload(JWT.EXP);
        if (issuedAt == null || expiresIn == null) {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            ApiResult result = (ApiResult) method.getReturnType().newInstance();
            return result.error(403, "Invalid Access Token");
        }
        if (System.currentTimeMillis() > (issuedAt.longValue() + expiresIn.longValue())) {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            ApiResult result = (ApiResult) method.getReturnType().newInstance();
            return result.error(403, "Expired Access Token");
        }
        return point.proceed();
    }

}
